package com.tools.common.container;

import com.tools.common.object.Note;
import org.jetbrains.annotations.NotNull;

import java.io.Serializable;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 自定义一个支持并发安全的 ConcurrentHashSet
 * 原理是内部封装一个 ConcurrentHashMap
 * */
@Note("自定义一个支持并发安全的 ConcurrentHashSet" +
        "原理是内部封装一个 ConcurrentHashMap")
public class ConcurrentHashSet<E> extends AbstractSet<E> implements Serializable {

    @Note("序列号 UID")
    private static final long serialVersionUID = 6334089401533916758L;

    @Note("内部使用 ConcurrentHashMap 实现")
    private final ConcurrentHashMap<E, Boolean> map;

    @Note("默认 value 常量")
    private static final Boolean VAL = true;

    /* ************************************************************************************************************
     *
     *          构造器
     *
     * ************************************************************************************************************
     * */

    public ConcurrentHashSet() {
        this.map = new ConcurrentHashMap<>();
    }

    public ConcurrentHashSet(int initialCapacity) {
        this.map = new ConcurrentHashMap<>(MapEnum.calcInitSize(initialCapacity));
    }

    public ConcurrentHashSet(int initialCapacity, float loadFactor) {
        this.map = new ConcurrentHashMap<>(MapEnum.calcInitSize(initialCapacity, loadFactor), loadFactor);
    }

    public ConcurrentHashSet(int initialCapacity, float loadFactor, int concurrencyLevel) {
        this.map = new ConcurrentHashMap<>(MapEnum.calcInitSize(initialCapacity, loadFactor), loadFactor, concurrencyLevel);
    }

    @SafeVarargs
    public ConcurrentHashSet(E... elements) {
        if(elements == null) {
            this.map = new ConcurrentHashMap<>();
            return;
        }
        int length = elements.length;
        if(length == 0) {
            this.map = new ConcurrentHashMap<>();
            return;
        }
        this.map = new ConcurrentHashMap<>(MapEnum.calcInitSize(length));
        private_put(elements);
    }

    public ConcurrentHashSet(Iterable<? extends E> elements) {
        if(elements == null) {
            this.map = new ConcurrentHashMap<>();
            return;
        }
        int size = RowKit.getIterableSize(elements);
        this.map = new ConcurrentHashMap<>(MapEnum.calcInitSize(size));
        private_put(elements);
    }

    /* ************************************************************************************************************
     *
     *          重写方法
     *
     * ************************************************************************************************************
     * */

    @Override
    public boolean add(E e) {
        return this.map.put(e, VAL) == null;
    }

    @Override
    public boolean remove(Object o) {
        return VAL.equals(this.map.remove(o));
    }

    @Override
    public void clear() {
        this.map.clear();
    }

    @Override
    public boolean contains(Object o) {
        return this.map.containsKey(o);
    }

    @NotNull
    @Override
    public Iterator<E> iterator() {
        return this.map.keySet().iterator();
    }

    @Override
    public int size() {
        return this.map.size();
    }

    @Override
    public boolean isEmpty() {
        return this.map.isEmpty();
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        if(c == null || c.isEmpty()) return false;
        boolean modified = false;
        for (E e : c) if (add(e)) modified = true;
        return modified;
    }

    @Override
    public boolean removeAll(Collection<?> elements) {
        if(elements == null || elements.isEmpty()) return false;
        boolean modified = false;
        for (Object o : elements) if(remove(o)) modified = true;
        return modified;
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        if(c == null || c.isEmpty()) return false;
        for (Object o : c) if(!contains(o)) return false;
        return true;
    }

    /* ************************************************************************************************************
     *
     *          自定义扩展方法
     *
     * ************************************************************************************************************
     * */

    @SafeVarargs
    public final boolean addAll (E... elements) {
        if(elements == null || elements.length == 0) return false;
        boolean modified = false;
        for (E e : elements) if (add(e)) modified = true;
        return modified;
    }

    public boolean addAll(OwnRows<? extends E> elements) {
        if(elements == null || elements.isEmpty()) return false;
        boolean modified = false;
        for (E e : elements) if (add(e)) modified = true;
        return modified;
    }

    public boolean addAll(Iterable<? extends E> elements) {
        if(elements == null) return false;
        Iterator<? extends E> iterator = elements.iterator();
        if(!iterator.hasNext()) return false;
        boolean modified = false;
        while (iterator.hasNext()) {
            if (add(iterator.next())) modified = true;
        }
        return modified;
    }

    @SafeVarargs
    public final boolean removeAll(E... elements) {
        if(elements == null || elements.length == 0) return false;
        boolean modified = false;
        for (Object o : elements) if(remove(o)) modified = true;
        return modified;
    }

    public boolean removeAll(OwnRows<?> elements) {
        if(elements == null || elements.isEmpty()) return false;
        boolean modified = false;
        for (Object o : elements) if(remove(o)) modified = true;
        return modified;
    }

    public boolean removeAll(Iterable<?> elements) {
        if(elements == null) return false;
        Iterator<?> iterator = elements.iterator();
        if(!iterator.hasNext()) return false;
        boolean modified = false;
        while (iterator.hasNext()) {
            if(remove(iterator.next())) modified = true;
        }
        return modified;
    }

    @SafeVarargs
    public final boolean containsAll(E... a) {
        if(a == null || a.length == 0) return false;
        for (Object o : a) if(!contains(o)) return false;
        return true;
    }

    public boolean containsAll(OwnRows<?> r) {
        if(r == null || r.isEmpty()) return false;
        for (Object o : r) if(!contains(o)) return false;
        return true;
    }

    public boolean containsAll(Iterable<?> c) {
        if(c == null) return false;
        Iterator<?> iterator = c.iterator();
        if(!iterator.hasNext()) return false;
        while (iterator.hasNext()) {
            if(!contains(iterator.next())) return false;
        }
        return true;
    }

    @SafeVarargs
    public final boolean containsAn(E... a) {
        if(a == null || a.length == 0) return false;
        for (Object o : a) if(contains(o)) return true;
        return false;
    }

    public boolean containsAny(Collection<?> c) {
        if(c == null || c.isEmpty()) return false;
        for (Object o : c) if(contains(o)) return true;
        return false;
    }

    public boolean containsAny(OwnRows<?> r) {
        if(r == null || r.isEmpty()) return false;
        for (Object o : r) if(contains(o)) return true;
        return false;
    }

    public boolean containsAny(Iterable<?> c) {
        if(c == null) return false;
        Iterator<?> iterator = c.iterator();
        if(!iterator.hasNext()) return false;
        while (iterator.hasNext()) {
            if(contains(iterator.next())) return true;
        }
        return false;
    }

    /* ************************************************************************************************************
     *
     *          私有逻辑
     *
     * ************************************************************************************************************
     * */

    @Note("将可迭代容器内的元素放入本容器中")
    private void private_put(Iterable<? extends E> elements) {
        for (E e : elements) {
            this.map.put(e, VAL);
        }
    }

    @Note("将数组内的元素放入本容器中")
    private void private_put(E[] elements) {
        for (E e : elements) {
            this.map.put(e, VAL);
        }
    }
}
